import { changeNumMoneyToChinese } from '@/utils/tool'
import dayjs from 'dayjs'
import isNil from 'lodash/isNil'
import cloneDeep from 'lodash/cloneDeep'
import isObject from 'lodash/isObject'
/**
 * import { precision as decimal, quantityDecimal } from '@/utils/precision.js'
 */
const decimal = 4
const quantityDecimal = 4

interface IPrintOptions {
  goodsList?: any[]
  shopName?: string
  [key: string]: any
}

/**
 * 生产环境production、开发环境development
 */
const environment: 'production' | 'development' = 'development'
/**
 * 页面最大显示高度-页面边距*2-页脚
 */
let pageHeight = 0

/**
 * table初始状态高度=offsetHeight
 */
let initTableHeight = 0

const getPaperLen = (size: string) => {
  switch (size) {
    case '297mm':
      return 34
    case '140mm':
      return 14
    case '93mm':
      return 8
    default:
      return 14
  }
}

/**
 * 根据类型格式化数据
 * @param data 格式化数据
 * @param type 格式化类型
 * @param params
 * @returns
 */
const formatData = (
  data = '',
  type?: string,
  params?: { format_option?: { chinese_number: string } }
) => {
  let retData = data ?? ''
  switch (type) {
    case 'currency':
      if (!!params) {
        if (params.format_option && params.format_option.chinese_number === '2') {
          retData = changeNumMoneyToChinese(data)
          return retData
        }
      }
      retData = Number(data).toFixed(decimal)
      break
    default:
      retData = data
      break
  }
  return retData
}

/**
 * 链式获取对象的值
 */
function getValueByPath(obj: any, path: string) {
  return path.split('.').reduce((prev, curr) => {
    return prev ? prev[curr] ?? '' : ''
  }, obj)
}

/**
 * 格式化整单折扣
 */
export function formatCoupon(data: IPrintOptions) {
  if (!data) return ''
  const { couponType, salesCoupon } = cloneDeep(data)
  if (salesCoupon === null || salesCoupon === undefined) {
    return ''
  } else if (couponType === 1) {
    return `${salesCoupon}%`
  } else if (couponType === 2) {
    return salesCoupon
  }
  return ''
}

/**
 * 处理数据，进行分页
 */
function formatPaging(doc: Document, data: IPrintOptions) {
  if (!doc) return

  const goodsList = (data.goodsList ?? []).map((i, index) => ({
    ...i,
    row_number: index + 1,
  }))

  /**
   * 存储分页数据
   */
  const pages: HTMLDivElement[] = []
  /**
   * table的新高度变化的偏移量=新高度-initTableHeight
   */
  let tableHeight = 0

  /**
   * 等待处理的组件下标
   */
  let currentIndex = 0
  /**
   * 表格处理的当前下标
   */
  let currentTableIndex = 0

  /**
   * 元素距离页面顶部的偏移量（保证第二页后的页面从页面顶部开始）
   */
  let pageOffset = 0

  /**
   * 是否溢出，当表格内容超过一页时，设置为true
   */
  let isOverflow = false

  /**
   * 计算高度，处理分页
   * 1. table下的内容始终保持与table的间距一致
   */
  function componenPaging() {
    /**
     * 所有组件的dom
     */
    const componentAll = Array.from(
      doc
        .cloneNode(true)
        .querySelectorAll('.print-paper__inner .print-element') as unknown as HTMLElement[]
    )
    console.log('任务', {
      currentIndex,
      currentTableIndex,
      componentAll,
    })
    tableHeight = 0
    const pageDom = document.createElement('div')
    pageDom.innerHTML = doc.querySelector('style').outerHTML
    const copyDom = doc.querySelector('.print-paper')!.cloneNode(true) as HTMLElement
    pageDom.appendChild(copyDom)

    const paperInner = copyDom.querySelector('.print-paper__inner') as HTMLElement
    paperInner.innerHTML = ''
    pages.push(pageDom)

    for (let index = currentIndex; index < componentAll.length; index++) {
      const item = componentAll[index]
      console.log(1122, item.outerHTML)

      /**
       * 当前组件的dom
       */
      const componentRootDom = item.parentElement as HTMLElement
      componentRootDom.setAttribute('data-init-top', componentRootDom.style.top)
      componentRootDom.style.top = `${parseFloat(componentRootDom.style.top) - pageOffset}px`
      currentIndex++
      console.log('componentRootDom', componentRootDom, item)
      const dataType = item.getAttribute('data-type')
      const dataBinding = item.getAttribute('data-binding')
      document.body.appendChild(pageDom)
      console.log('dataType', dataType)
      if (dataType === 'table') {
        paperInner.appendChild(componentRootDom)
        const theads = componentRootDom.querySelectorAll('colgroup col') as unknown as HTMLElement[]
        const tbody_td = Array.from(
          componentRootDom.querySelectorAll('tbody .row-title td')
        ) as HTMLElement[]
        const tbody = componentRootDom.querySelector('tbody')
        if (!tbody) return
        console.log('theads', theads, tbody_td)
        /**
         * 表格列的配置
         */
        const columns = tbody_td.map((i) => {
          const td_div = i.querySelector('div')
          const label = td_div?.innerText.trim()
          const col = componentRootDom.querySelector(
            `colgroup col[data-label=${label}]`
          ) as HTMLElement
          const binding = col?.getAttribute('data-binding') ?? ''
          const type = col?.getAttribute('data-format_type') ?? ''
          const width = parseFloat(i.style.width) ?? 0
          if (width && col) {
            col.style.minWidth = `${width}px`
            col.style.width = `${width}px`
          }
          return {
            label,
            binding,
            width,
            type,
          }
        })
        console.log('表格列的配置columns', columns)
        /**
         * 获取需要多行展示的字段，只支持一个数据多行显示
         */
        const keys = columns
          .filter((i) => /\[\]/.test(i.binding))
          .map((i) => {
            return i.binding.split('[]')[0]
          })
          .filter((item, index, arr) => arr.indexOf(item) === index)[0]
        console.log('获取需要多行展示的字段keys', keys)
        // 删除无用的子元素
        const tbody_children = tbody?.children ?? []
        // // 循环检查并删除没有数据的子元素
        for (let i = 0; i < tbody_children.length; i++) {
          if (tbody_children[i].className == 'row-data' || !tbody_children[i].className) {
            tbody?.removeChild(tbody_children[i])
          }
        }
        /**
         * 表格处理的开始下标
         */
        const startTableIndex = currentTableIndex
        /**
         * 处理本页小计和合计数据
         */
        function aggregateStatistics(arr?: any[]) {
          //向表格的本页小计/合计行中添加数量或金额
          const forEachFillTd = (dom: HTMLTableCellElement[], attr: string, value: string) => {
            for (let i = 0; i < dom.length; i++) {
              const attrName = dom[i].getAttribute('data-label')?.trim()
              if (attrName === attr) {
                if (attr === '合计') {
                  let text =
                    dom[i].textContent.indexOf('金额大写') > -1 ||
                    dom[i].dataset.format_type === '金额大写'
                      ? changeNumMoneyToChinese(value)
                      : Number(value || 0).toFixed(decimal)
                  dom[i].textContent = `合计：${text}`
                } else {
                  dom[i].textContent = value
                }
                return
              }
            }
          }

          /**
           * 当前页处理的数据
           */
          const currentTotalArr = (arr ?? goodsList).slice(startTableIndex, currentTableIndex)
          // 每页本页小计
          // 每页金额小计
          const totalAmount = keys
            ? currentTotalArr.reduce((previous, current) => {
                let total = 0
                for (const i of current[keys] ?? []) {
                  total += Number(i.amount)
                }
                return previous + total
              }, 0)
            : currentTotalArr.reduce((previous, current) => {
                return Number(previous + (Number(current.amount) || 0))
              }, 0)
          // 每页数量小计
          const totalQtys = keys
            ? currentTotalArr.reduce((previous, current) => {
                let total = 0
                for (const i of current[keys] ?? []) {
                  total += Number(i.quantity)
                }
                return previous + total
              }, 0)
            : currentTotalArr.reduce((previous, current) => {
                return Number(previous + (Number(current.quantity) || 0))
              }, 0)

          // 处理本页小计
          const subTotal = tbody?.querySelector('.row-subtotal')
          if (subTotal && subTotal.innerHTML !== '') {
            const totalEle = subTotal.querySelectorAll('td') as unknown as HTMLTableCellElement[]
            if (totalEle.length > 0) {
              forEachFillTd(totalEle, '数量', Number(totalQtys).toFixed(quantityDecimal))
              forEachFillTd(totalEle, '金额', totalAmount.toFixed(decimal))
            }
          }
          // 处理合计
          const rowTotal = tbody?.querySelector('.row-total')
          if (rowTotal && rowTotal.innerHTML !== '') {
            const totalEle = rowTotal.querySelectorAll('td') as unknown as HTMLTableCellElement[]
            if (totalEle.length > 0) {
              const amountAll =
                (isNil(data.para?.allAmount) ? data.para?.amount : data.para?.allAmount) ?? 0
              forEachFillTd(totalEle, '合计', amountAll)
              forEachFillTd(
                totalEle,
                '数量',
                isNil(data.para?.allcount)
                  ? Number(data.para?.quantity ?? 0).toFixed(quantityDecimal)
                  : Number(data.para?.allcount ?? 0).toFixed(quantityDecimal)
              )
              forEachFillTd(totalEle, '金额', Number(amountAll).toFixed(decimal))
            }
          }
        }

        // 渲染每一行的表格数据
        for (let index = currentTableIndex; index < goodsList.length; index++) {
          currentTableIndex++
          const row = goodsList[index]
          /**
           * 获取需要多行显示的数据
           */
          const groupData = row[keys] ?? []
          /**
           * 需要多行显示的数据key
           */
          const group_keys = columns
            .filter((i) => {
              return i.binding.indexOf('[]') !== -1
            })
            .map((i) => {
              return i.binding.split('[]')[1]
            })
          console.log('需要多行显示的数据group', groupData, group_keys, columns)
          const trDom = document.createElement('tr')
          const dataFirstRow = tbody?.querySelector('.row-subtotal')
          const rootTds = []

          // 渲染td数据
          for (let index = 0; index < columns.length; index++) {
            const item = columns[index]
            let td = document.createElement('td')
            let divDom = document.createElement('div')
            if (item.binding === 'note') {
              /**
               * 限制最大高度：当内容过长溢出时，会导致页面向y轴缩小（此处需要评估是否这么做）
               * 不限制最大高度：小型纸张，如三等分，内容过长会导致页面无法正常绘制
               */
              divDom.style.maxHeight = `${pageHeight / 4}px`
            }
            if (groupData.length > 0 && new RegExp(`^${keys}\\[\\]`).test(item.binding)) {
              divDom.textContent = formatData(
                groupData[0][`${item.binding.split('[]')[1]}`],
                item.type
              )
              td.appendChild(divDom)
              trDom.appendChild(td)
              dataFirstRow?.insertAdjacentElement('beforebegin', trDom)
            } else {
              let val = ''
              if (/\./.test(item.binding)) {
                // 链式获取对象的值,如goods.goodsName
                val = getValueByPath(row, item.binding)
              } else {
                val = row[`${item.binding}`] ?? ''
              }
              divDom.textContent = formatData(val, item.type)
              td.appendChild(divDom)
              trDom.appendChild(td)
              rootTds.push(td)
            }
          }
          dataFirstRow?.insertAdjacentElement('beforebegin', trDom)
          aggregateStatistics()
          // 计算高度是否超出当前页，表格计算内容高度
          const h = componentRootDom.offsetHeight + componentRootDom.offsetTop
          tableHeight = componentRootDom.offsetHeight - initTableHeight
          console.log('tableHeight', tableHeight, initTableHeight, componentRootDom.offsetHeight)
          if (h > pageHeight) {
            if (isOverflow) {
              alert('表格内容数据过长，暂时无法进行打印/预览')
              return
            }
            // 需要分页删除合计行
            const rowTotalTr = tbody.querySelector('.row-total')
            rowTotalTr && tbody.removeChild(rowTotalTr)
            aggregateStatistics()
            currentTableIndex--
            currentIndex--
            const datInitTop = componentRootDom.getAttribute('data-init-top')
            console.log(666, datInitTop)
            pageOffset = datInitTop ? parseFloat(datInitTop) : componentRootDom.offsetTop
            trDom.remove()
            if (environment === 'production') {
              document.body.removeChild(pageDom)
            }
            isOverflow = true
            componenPaging()
            return
          }
          isOverflow = false
          // 合并单元格，多条数据再次渲染表格
          if (groupData.length > 1) {
            for (let i = 1; i < groupData.length; i++) {
              for (const element of rootTds) {
                element.setAttribute('rowspan', `${i + 1}`)
              }
              const trDom = document.createElement('tr')
              trDom.classList.add('border-left')
              const item = groupData[i]
              // 渲染td数据
              for (const key of group_keys) {
                let td = document.createElement('td')
                const obj = columns.find((i) => {
                  return i.binding === `${keys}[0]${key}`
                })
                let divDom = document.createElement('div')
                divDom.textContent = formatData(item[key], obj?.type)
                td.appendChild(divDom)
                trDom.appendChild(td)
              }
              dataFirstRow?.insertAdjacentElement('beforebegin', trDom)
              aggregateStatistics()
              // 计算高度是否超出当前页，表格计算内容高度
              const h = componentRootDom.offsetHeight + componentRootDom.offsetTop
              tableHeight = componentRootDom.offsetHeight - initTableHeight
              if (h > pageHeight) {
                // 多行超出了，截取数据到下一页显示
                const rowTotalTr = tbody.querySelector('.row-total')
                rowTotalTr && tbody.removeChild(rowTotalTr)
                // 筛选已经渲染的数据
                console.log('9996', groupData.slice(0, i), i)
                const arr = cloneDeep(goodsList)
                arr[index][keys] = groupData.slice(0, i)
                aggregateStatistics(arr)
                // 过滤掉已经渲染的数据进行赋值
                goodsList[index][keys] = groupData.slice(i)
                currentTableIndex--
                currentIndex--
                const datInitTop = componentRootDom.getAttribute('data-init-top')
                console.log(666, datInitTop)
                pageOffset = datInitTop ? parseFloat(datInitTop) : componentRootDom.offsetTop
                for (const element of rootTds) {
                  element.setAttribute('rowspan', `${i}`)
                }
                trDom.remove()
                if (environment === 'production') {
                  document.body.removeChild(pageDom)
                }
                console.log('下标', i, data, trDom)
                componenPaging()
                return
              }
            }
          }
        }
      } else if (dataType === 'customTable') {
        // 自定义表格
        const tds = Array.from(item.querySelectorAll('tr td'))
        for (const td of tds) {
          const binding = td.dataset.binding
          if (binding) {
            const span = td.querySelector('span')
            if (span) {
              span.innerText = data[binding]
            }
          }
        }
        paperInner.appendChild(componentRootDom)
      } else if (dataType === 'pagination') {
        paperInner.appendChild(componentRootDom)
      } else if (dataType === 'datetime') {
        // --------处理打单时间--------
        const formatType = JSON.parse(item.getAttribute('data-format_option'))
        item.textContent = dayjs().format(formatType?.template ?? 'YYYY-MM-DD HH:mm:ss')
      } else if (dataType === 'image') {
        if (dataBinding === 'shopLogo') {
          const img = item.querySelector('img')
          img?.setAttribute('src', data.shopLogo)
        }
      } else if (
        dataType === 'customText' ||
        dataType === 'title' ||
        dataType === 'view' ||
        dataType === 'line'
      ) {
        // 自定义文案
      } else if (dataBinding) {
        const spanDom = item.querySelector('span')
        switch (dataBinding) {
          case 'customerAddress':
          case 'fullShopAddress':
          case 'shopAddress':
            // 地址
            let address = ''
            if (isObject(data[dataBinding])) {
              // 对账打印
              const { province = '', city = '', region = '', shopAddress = '' } = data[dataBinding]
              address = `${province}${city}${region}${shopAddress}`
            } else if ('shopAddress' === dataBinding) {
              const { province = '', city = '', region = '', shopAddress = '' } = data
              address = `${province}${city}${region}${shopAddress}`
            } else {
              address = data[dataBinding]
            }

            if (spanDom) {
              spanDom.innerText = address
            }
            break
          case 'bill_create_time':
            // 账单生成时间
            if (spanDom) {
              spanDom.innerText = dayjs().format('YYYY-MM-DD HH:mm:ss')
            }
            break
          default:
            if (spanDom) {
              // 链式获取对象的值,如goods.goodsName
              spanDom.innerText = /\./.test(dataBinding)
                ? getValueByPath(data, dataBinding)
                : data[dataBinding] ?? ''
            }
            break
        }
      }
      if (dataType !== 'table') {
        componentRootDom.style.top = `${parseFloat(componentRootDom.style.top) + tableHeight}px`
      }

      paperInner.appendChild(componentRootDom)
      // 内容只比较初始高度
      const h = parseFloat(componentRootDom!.style.height) + componentRootDom!.offsetTop
      if (h > pageHeight) {
        if (isOverflow) {
          alert('表格内容数据过长，暂时无法进行打印/预览')
          return
        }
        // 超出了需要换页显示，并删除当前渲染的元素
        const datInitTop = componentRootDom.getAttribute('data-init-top')
        pageOffset = datInitTop ? parseFloat(datInitTop) : componentRootDom.offsetTop
        paperInner.removeChild(componentRootDom)
        currentIndex--
        if (environment === 'production') {
          document.body.removeChild(pageDom)
        }
        isOverflow = true
        componenPaging()
        return
      } else {
        isOverflow = false
      }
    }
  }
  componenPaging()
  return isOverflow ? [] : pages
}

function printHtml(html: string, data: IPrintOptions) {
  let domContainer: null | HTMLElement = null
  /**
   * 针对节点进行排序
   * @param doc
   */
  const fileTemplateAllPage = (doc: Document) => {
    const printFoot = doc.getElementsByClassName('print-footer')[0]
    const vdrContainerDom = doc.getElementsByClassName('vdr-container')
    const vdrArr: HTMLElement[] = []
    for (let i = 0; i < vdrContainerDom.length; i++) {
      vdrArr.push(vdrContainerDom[i] as HTMLElement)
    }
    vdrArr.sort(function (a, b) {
      const aTop = parseFloat(a?.style?.top) ?? 0
      const bTop = parseFloat(b?.style?.top) ?? 0
      return aTop - bTop
    })
    vdrArr.forEach((item) => {
      printFoot.insertAdjacentElement('beforebegin', item)
    })
  }
  let doc: Document | null = new DOMParser().parseFromString(html, 'text/html')
  // 删除无用的节点
  const resizers = doc.querySelectorAll('p.resizer,.vdr-handle')
  for (const p of resizers) {
    p.remove()
  }
  // 删除多余的表格列
  const customTable = doc.querySelector('.print-element[data-binding=custom-table]') as HTMLElement
  if (customTable) {
    // 设置表格最小高度，且高度自适应
    const tableContainer = customTable.parentElement as HTMLElement
    initTableHeight = parseFloat(tableContainer.style.height)
    tableContainer.style.minHeight = `${initTableHeight}px`
    tableContainer.style.height = `auto`
    customTable.style.height = `auto`
    const labels = Array.from(customTable?.querySelectorAll('.row-title td')).map((i) =>
      i.innerText.trim()
    )
    const cols = customTable?.querySelectorAll('colgroup col')
    for (const item of cols) {
      if (!labels.includes(item.dataset.label.trim())) {
        item.remove()
      }
    }
  }
  fileTemplateAllPage(doc)
  console.log('fileTemplateAllPage', doc.documentElement.innerHTML)
  // 1. 获取页面尺寸
  domContainer = document.createElement('div')
  domContainer.innerHTML = doc.documentElement.innerHTML
  document.body.appendChild(domContainer)
  const page: HTMLElement | null = domContainer.querySelector('.print-paper')
  if (!page) return
  const pageStyle = window.getComputedStyle(page)
  console.log(3333, pageStyle.height, page.offsetHeight)
  // 获取页脚高度
  let printFooter: HTMLElement | null = domContainer.querySelector('.print-footer')
  pageHeight =
    page.offsetHeight -
    parseFloat(pageStyle.paddingTop) -
    parseFloat(pageStyle.paddingBottom) -
    (printFooter ? parseFloat(printFooter.style.bottom) : 0)

  // 复制一份页脚dom
  let paginationClone: HTMLElement | null = doc
    .querySelector('.print-element[data-type=pagination]')
    ?.parentNode?.cloneNode(true) as HTMLElement
  if (paginationClone) {
    doc.querySelector('.print-element[data-type=pagination]')?.parentNode?.remove?.()
  }

  const paperSettingsType = {
    pageHeight,
    padding: page.style.padding,
    width: page.style.width,
    height: page.style.height,
    len: getPaperLen(`${page.style.height}`),
    type: page.getAttribute('data-name'),
  }

  console.log('获取页面信息', paperSettingsType)
  document.body.removeChild(domContainer)
  domContainer = null
  // 2. 格式化数据
  const coupon = formatCoupon(data)
  // 3. 计算需要打印的页数
  let pages: HTMLElement[] | null = formatPaging(doc, { ...data, coupon }) ?? []
  console.log('pages', pages)
  const templates: string[] = []
  const pagination = paginationClone?.querySelector('.print-element[data-type=pagination]')
  const dataValue = pagination?.getAttribute('data-value')
  pages.forEach((element, index) => {
    if (dataValue) {
      if (paginationClone) {
        // 4. 生成页脚页码
        const pagination = paginationClone.cloneNode(true) as HTMLElement
        const text = dataValue
          .replace('{PageNO}', `${index + 1}`)
          .replace('{PageCount}', `${pages!.length}`)
        console.log('root', element.querySelector('.print-paper__inner'))
        const content: HTMLElement | null = pagination.querySelector('.inline-flex')
        if (content) {
          content.innerText = text
        }
        element.querySelector('.print-paper__inner')?.appendChild(pagination)
      }
    }
    templates.push(element.innerHTML)
    if (environment === 'production') {
      element.remove() // 发布需要销毁
    }
  })

  printFooter = null
  pages = null
  doc = null
  paginationClone = null
  initTableHeight = 0
  pageHeight = 0
  return {
    templates,
    paperSettingsType,
  }
}

export default printHtml
